package org.cleverframe.modules.erp.service;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.cleverframe.common.persistence.Page;
import org.cleverframe.common.persistence.entity.BaseEntity;
import org.cleverframe.common.service.BaseService;
import org.cleverframe.common.vo.AjaxMessage;
import org.cleverframe.modules.erp.ErpBeanNames;
import org.cleverframe.modules.erp.dao.RawMaterialInfoDao;
import org.cleverframe.modules.erp.dao.RawmaterialWarehouseDao;
import org.cleverframe.modules.erp.entity.RawMaterialInfo;
import org.cleverframe.modules.erp.entity.RawmaterialWarehouse;
import org.cleverframe.modules.erp.entity.Supplier;
import org.cleverframe.modules.sys.SysBeanNames;
import org.cleverframe.modules.sys.dao.DictDao;
import org.cleverframe.modules.sys.entity.Dict;
import org.cleverframe.modules.sys.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

/**
 * 原料入库申请单Service<br>
 * @author LiZW
 * @version 2016年1月6日 下午2:10:00
 */
@Service(ErpBeanNames.RawmaterialWarehouseService)
public class RawmaterialWarehouseService extends BaseService
{
    /** 日志对象 */
    private final static Logger logger = LoggerFactory.getLogger(RawmaterialWarehouseService.class);
    
    /** 审核人的字典类型 */
    public static final String AUDITOR_DICT_TYPE = "原料入库申请审核流程";
    /** 审核人的字典名称 */
    public static final String AUDITOR_DICT_KEY = "财务部门审核";
    
    @Autowired
    @Qualifier(ErpBeanNames.RawmaterialWarehouseDao)
    private RawmaterialWarehouseDao rawmaterialWarehouseDao;

    @Autowired
    @Qualifier(ErpBeanNames.RawMaterialInfoDao)
    private RawMaterialInfoDao rawMaterialInfoDao;
    
    @Autowired
    @Qualifier(SysBeanNames.DictDao)
    private DictDao dictDao;
    
    /**
     * 分页查询原料入库单<br>
     * @param page 分页数据
     * @param warehouseNo 查询参数：入库单号
     * @param rawmaterialCode 查询参数：原料编码
     * @param name 查询参数：原料名称
     * @param auditorState 查询参数：审核状态
     * @param startDate 查询参数：入库时间最小
     * @param endDate 查询参数：入库时间最大
     * @param supplierName 查询参数：供应商名称
     * @return
     */
    public Page<Map<Object, Object>> findRawmaterialWarehouseByPage(
            Page<Map<Object, Object>> page, 
            String warehouseNo, 
            String rawmaterialCode, 
            String name,
            String auditorState, 
            Date startDate, 
            Date endDate, 
            String supplierName)
    {
        return rawmaterialWarehouseDao.findRawmaterialWarehouseByPage(page, warehouseNo, rawmaterialCode, name, auditorState, startDate, endDate, supplierName);
    }
    
    /**
     * 查询当前用户需要审核的原料入库单<br>
     * @param page 分页数据
     * @param warehouseNo 查询参数：入库单号
     * @param rawmaterialCode 查询参数：原料编码
     * @param name 查询参数：原料名称
     * @param startDate 查询参数：入库时间最小
     * @param endDate 查询参数：入库时间最大
     * @param supplierName 查询参数：供应商名称
     * @param userId 查询参数：用户ID
     * @return
     */
    public Page<Map<Object, Object>> findAuditRawmaterialWarehouseByPage(
            Page<Map<Object, Object>> page, 
            String warehouseNo, 
            String rawmaterialCode, 
            String name,
            Date startDate, 
            Date endDate, 
            String supplierName,
            Long userId)
    {
        return rawmaterialWarehouseDao.findAuditRawmaterialWarehouseByPage(page, warehouseNo, rawmaterialCode, name, startDate, endDate, supplierName, userId);
    }
    
    
    /**
     * 保存原料入库申请单<br>
     * 1.初始化审核时填写的数据<br>
     * 2.验证原料存在<br>
     * 3.验证 “原料”、“供应商”、“流程审核人” 存在<br>
     * 4.生成原料入库申请单号码<br>
     */
    public synchronized boolean addRawmaterialWarehouse(RawmaterialWarehouse rawmaterialWarehouse, AjaxMessage message)
    {
        // 初始化审核时填写的数据
        rawmaterialWarehouse.setAuditorState(RawmaterialWarehouse.PENDING_AUDIT);
        rawmaterialWarehouse.setUnitPrice(new BigDecimal(0));
        rawmaterialWarehouse.setAggregateAmount(new BigDecimal(0));
        rawmaterialWarehouse.setIsInvoice(RawmaterialWarehouse.INVOICE_YES);
        rawmaterialWarehouse.setIsHistory(RawmaterialWarehouse.HISTORY_NO);
        rawmaterialWarehouse.setIsChange(RawmaterialWarehouse.CHANGE_NO);
        
        // 验证
        RawMaterialInfo rawMaterialInfo = rawMaterialInfoDao.getRawMaterialInfoByCode(rawmaterialWarehouse.getRawmaterialCode());
        if (rawMaterialInfo == null)
        {
            message.setMessage("原料[" + rawmaterialWarehouse.getName() + "]不存在");
            return false;
        }
        
        Supplier supplier = rawmaterialWarehouseDao.getHibernateDao().getEntity(Supplier.class, rawmaterialWarehouse.getSupplierId());
        if (supplier == null)
        {
            message.setMessage("供应商不存在不存在");
            return false;
        }
        
        User user = rawmaterialWarehouseDao.getHibernateDao().getEntity(User.class, rawmaterialWarehouse.getAuditorId());
        if (user == null)
        {
            message.setMessage("流程审核人不存在");
            return false;
        }
        
        // 生成原料入库申请单号码
        String warehouseMaxNo = rawmaterialWarehouseDao.getWarehouseMaxNo();
        StringBuilder str = new StringBuilder();
        for (int i = 0; i < RawmaterialWarehouse.NO_NUMBER_LENGTH; i++)
        {
            str.append('0');
        }
        if(StringUtils.isBlank(warehouseMaxNo))
        {
            str.append('1');
        }
        else
        {
            warehouseMaxNo = warehouseMaxNo.replace(RawmaterialWarehouse.NO_PREFIX, "").replace(RawmaterialWarehouse.NO_SUFFIX, "");
            int max = NumberUtils.toInt(warehouseMaxNo, 0) + 1;
            str.append(max);
        }
        warehouseMaxNo = str.toString().substring(str.length() - RawmaterialWarehouse.NO_NUMBER_LENGTH);
        warehouseMaxNo = RawmaterialWarehouse.NO_PREFIX + warehouseMaxNo + RawmaterialWarehouse.NO_SUFFIX;
        rawmaterialWarehouse.setWarehouseNo(warehouseMaxNo);
        
        // 保存数据
        rawmaterialWarehouseDao.getHibernateDao().save(rawmaterialWarehouse);
        return true;
    }
    
    /**
     * 更新原料入库申请单<br>
     * 1.验证修改的原料入库申请单存在，而且审核状态只能是：(1：等待审核；4：审核完成-驳回)<br>
     * 2.初始化审核时填写的数据<br>
     * 3.验证原料存在<br>
     * 4.验证 “原料”、“供应商”、“流程审核人” 存在<br>
     * 5.原料入库申请单编号不能修改<br>
     * */
    public boolean updateRawmaterialWarehouse(RawmaterialWarehouse rawmaterialWarehouse, AjaxMessage message)
    {
        RawmaterialWarehouse oldRawmaterialWarehouse = rawmaterialWarehouseDao.getHibernateDao().get(rawmaterialWarehouse.getId());
        if (oldRawmaterialWarehouse == null)
        {
            message.setMessage("原料入库申请单不存在");
            return false;
        }
        if (new Character(RawmaterialWarehouse.PENDING_AUDIT).equals(oldRawmaterialWarehouse.getAuditorState()) == false
                && new Character(RawmaterialWarehouse.AUDIT_REJECT).equals(oldRawmaterialWarehouse.getAuditorState()) == false)
        {
            message.setMessage("原料入库申请单审核状态必须是“等待审核”、“驳回”才能修改");
            return false;
        }
        
        if (oldRawmaterialWarehouse.getWarehouseNo().equals(rawmaterialWarehouse.getWarehouseNo()) == false)
        {
            message.setMessage("不能修改原料入库申请单编号");
            return false;
        }
        
        // 初始化审核时填写的数据
        rawmaterialWarehouse.setAuditorState(RawmaterialWarehouse.PENDING_AUDIT);
        rawmaterialWarehouse.setUnitPrice(new BigDecimal(0));
        rawmaterialWarehouse.setAggregateAmount(new BigDecimal(0));
        rawmaterialWarehouse.setIsInvoice(RawmaterialWarehouse.INVOICE_YES);
        rawmaterialWarehouse.setIsHistory(RawmaterialWarehouse.HISTORY_NO);
        rawmaterialWarehouse.setIsChange(oldRawmaterialWarehouse.getIsChange());
        
        // 验证
        RawMaterialInfo rawMaterialInfo = rawMaterialInfoDao.getRawMaterialInfoByCode(rawmaterialWarehouse.getRawmaterialCode());
        if (rawMaterialInfo == null)
        {
            message.setMessage("原料[" + rawmaterialWarehouse.getName() + "]不存在");
            return false;
        }
        
        Supplier supplier = rawmaterialWarehouseDao.getHibernateDao().getEntity(Supplier.class, rawmaterialWarehouse.getSupplierId());
        if (supplier == null)
        {
            message.setMessage("供应商不存在不存在");
            return false;
        }
        
        User user = rawmaterialWarehouseDao.getHibernateDao().getEntity(User.class, rawmaterialWarehouse.getAuditorId());
        if (user == null)
        {
            message.setMessage("流程审核人不存在");
            return false;
        }
        
        // 更新数据
        rawmaterialWarehouseDao.getHibernateDao().getSession().evict(oldRawmaterialWarehouse);
        rawmaterialWarehouseDao.getHibernateDao().getSession().update(rawmaterialWarehouse);
        return true;
    }
    
    /**
     * 删除原料入库申请单<br>
     * 1.验证修改的原料入库申请单存在，而且审核状态只能是：(1：等待审核；4：审核完成-驳回)<br>
     * 2.删除必须删除历史单<br>
     * */
    public boolean deleteRawmaterialWarehouse(RawmaterialWarehouse rawmaterialWarehouse, AjaxMessage message)
    {
        // 验证
        RawmaterialWarehouse oldRawmaterialWarehouse = rawmaterialWarehouseDao.getHibernateDao().get(rawmaterialWarehouse.getId());
        if (oldRawmaterialWarehouse == null)
        {
            message.setMessage("原料入库申请单不存在");
            return false;
        }
        if (new Character(RawmaterialWarehouse.PENDING_AUDIT).equals(oldRawmaterialWarehouse.getAuditorState()) == false
                && new Character(RawmaterialWarehouse.AUDIT_REJECT).equals(oldRawmaterialWarehouse.getAuditorState()) == false)
        {
            message.setMessage("原料入库申请单审核状态必须是“等待审核”、“驳回”才能删除");
            return false;
        }
        
        // 删除历史单
        String warehouseNo = oldRawmaterialWarehouse.getWarehouseNo() + RawmaterialWarehouse.HISTORY_NO_SUFFIX;
        RawmaterialWarehouse historyRawmaterialWarehouse = rawmaterialWarehouseDao.getRawmaterialWarehouseByWarehouseNo(warehouseNo);
        if (historyRawmaterialWarehouse != null)
        {
            rawmaterialWarehouseDao.getHibernateDao().delete(historyRawmaterialWarehouse);
        }
        // 删除
        rawmaterialWarehouseDao.getHibernateDao().delete(oldRawmaterialWarehouse);
        return true;
    }
    
    /**
     * 审核原料入库申请单--审核通过处理<br>
     * 1.验证修改的原料入库申请单存在，而且审核状态只能是：(1：等待审核；2：审核中-已经审核过但是没有完成)<br>
     * 2.验证 “原料”、“供应商”、“流程审核人” 存在<br>
     * 3.验证审核数据正确<br>
     * 4.修改审核状态，更新原料入库申请单<br>
     * */
    public synchronized boolean auditResultPass(RawmaterialWarehouse rawmaterialWarehouse, AjaxMessage message)
    {
        // 验证
        RawmaterialWarehouse oldRawmaterialWarehouse = rawmaterialWarehouseDao.getHibernateDao().get(rawmaterialWarehouse.getId());
        if (oldRawmaterialWarehouse == null)
        {
            message.setMessage("原料入库申请单不存在");
            return false;
        }
        if (new Character(RawmaterialWarehouse.PENDING_AUDIT).equals(oldRawmaterialWarehouse.getAuditorState()) == false
                && new Character(RawmaterialWarehouse.AUDIT_ING).equals(oldRawmaterialWarehouse.getAuditorState()) == false)
        {
            message.setMessage("原料入库申请单审核状态必须是“等待审核”、“审核中”才能审核");
            return false;
        }
        
        // 验证
        RawMaterialInfo rawMaterialInfo = rawMaterialInfoDao.getRawMaterialInfoByCode(rawmaterialWarehouse.getRawmaterialCode());
        if (rawMaterialInfo == null || rawMaterialInfo.getDelFlag().equals(BaseEntity.DEL_FLAG_NORMAL) == false)
        {
            message.setMessage("原料[" + rawmaterialWarehouse.getName() + "]不存在或被删除");
            return false;
        }
        
        Supplier supplier = rawmaterialWarehouseDao.getHibernateDao().getEntity(Supplier.class, rawmaterialWarehouse.getSupplierId());
        if (supplier == null)
        {
            message.setMessage("供应商不存在不存在");
            return false;
        }
        
        User user = rawmaterialWarehouseDao.getHibernateDao().getEntity(User.class, rawmaterialWarehouse.getAuditorId());
        if (user == null)
        {
            message.setMessage("流程审核人不存在");
            return false;
        }
        
        // 验证审核数据
        if (rawmaterialWarehouse.getUnitPrice().longValue() < 0L)
        {
            message.setMessage("原料单价不能小于0");
            return false;
        }
        
        // 审核通过
        BigDecimal aggregateAmount = rawmaterialWarehouse.getUnitPrice().multiply(rawmaterialWarehouse.getQuantity());
        rawmaterialWarehouse.setAggregateAmount(aggregateAmount);
        if (rawmaterialWarehouse.getAggregateAmount().longValue() < 0L)
        {
            message.setMessage("应付金额不能小于0");
            return false;
        }
        rawmaterialWarehouse.setAuditorState(RawmaterialWarehouse.AUDIT_PASS);
        rawmaterialWarehouse.setIsHistory(RawmaterialWarehouse.HISTORY_NO);
        rawmaterialWarehouse.setIsChange(oldRawmaterialWarehouse.getIsChange());
        // TODO 更新库存

        //更新
        rawmaterialWarehouseDao.getHibernateDao().getSession().evict(oldRawmaterialWarehouse);
        rawmaterialWarehouseDao.getHibernateDao().update(rawmaterialWarehouse);
        return true;
    }

    /**
     * 审核原料入库申请单--驳回处理<br>
     * 1.验证修改的原料入库申请单存在，而且审核状态只能是：(1：等待审核；2：审核中-已经审核过但是没有完成)<br>
     * 2.验证 “原料”、“供应商”、“流程审核人” 存在<br>
     * 3.初始化审核数据正确<br>
     * 4.修改审核状态<br>
     * */
    public synchronized boolean auditResultReject(RawmaterialWarehouse rawmaterialWarehouse, AjaxMessage message)
    {
        // 验证
        RawmaterialWarehouse oldRawmaterialWarehouse = rawmaterialWarehouseDao.getHibernateDao().get(rawmaterialWarehouse.getId());
        if (oldRawmaterialWarehouse == null)
        {
            message.setMessage("原料入库申请单不存在");
            return false;
        }
        if (new Character(RawmaterialWarehouse.PENDING_AUDIT).equals(oldRawmaterialWarehouse.getAuditorState()) == false
                && new Character(RawmaterialWarehouse.AUDIT_ING).equals(oldRawmaterialWarehouse.getAuditorState()) == false)
        {
            message.setMessage("原料入库申请单审核状态必须是“等待审核”、“审核中”才能审核");
            return false;
        }
        
        // 验证
        RawMaterialInfo rawMaterialInfo = rawMaterialInfoDao.getRawMaterialInfoByCode(rawmaterialWarehouse.getRawmaterialCode());
        if (rawMaterialInfo == null || rawMaterialInfo.getDelFlag().equals(BaseEntity.DEL_FLAG_NORMAL) == false)
        {
            message.setMessage("原料[" + rawmaterialWarehouse.getName() + "]不存在或被删除");
            return false;
        }
        
        Supplier supplier = rawmaterialWarehouseDao.getHibernateDao().getEntity(Supplier.class, rawmaterialWarehouse.getSupplierId());
        if (supplier == null)
        {
            message.setMessage("供应商不存在不存在");
            return false;
        }
        
        User user = rawmaterialWarehouseDao.getHibernateDao().getEntity(User.class, rawmaterialWarehouse.getAuditorId());
        if (user == null)
        {
            message.setMessage("流程审核人不存在");
            return false;
        }
        
        // 初始化审核时填写的数据
        rawmaterialWarehouse.setUnitPrice(new BigDecimal(0));
        rawmaterialWarehouse.setAggregateAmount(new BigDecimal(0));
        rawmaterialWarehouse.setIsInvoice(RawmaterialWarehouse.INVOICE_YES);
        rawmaterialWarehouse.setIsHistory(RawmaterialWarehouse.HISTORY_NO);
        rawmaterialWarehouse.setIsChange(oldRawmaterialWarehouse.getIsChange());
        
        // 设置审核驳回
        rawmaterialWarehouse.setAuditorState(RawmaterialWarehouse.AUDIT_REJECT);
        
        //更新
        rawmaterialWarehouseDao.getHibernateDao().getSession().evict(oldRawmaterialWarehouse);
        rawmaterialWarehouseDao.getHibernateDao().update(rawmaterialWarehouse);
        return true;
    }
    
    /**
     * 变更原料入库申请单<br>
     * 1.验证修改的原料入库申请单存在，而且审核状态只能是：(3：审核完成-通过)<br>
     * 2.验证变更的申请单 “原料”、“供应商”、“流程审核人” 存在<br>
     * 3.初始化变更的申请单审核时填写的数据<br>
     * 4.修改原料入库申请单原单的原料编号(增加历史信息)，并且设置变更的申请单的编号<br>
     * 5.数据库保存变更的申请单<br>
     * */
    public boolean changeRawmaterialWarehouse(RawmaterialWarehouse rawmaterialWarehouse, AjaxMessage message)
    {
        // 验证
        RawmaterialWarehouse oldRawmaterialWarehouse = rawmaterialWarehouseDao.getHibernateDao().get(rawmaterialWarehouse.getId());
        if (oldRawmaterialWarehouse == null)
        {
            message.setMessage("原料入库申请单不存在");
            return false;
        }
        if (new Character(RawmaterialWarehouse.AUDIT_PASS).equals(oldRawmaterialWarehouse.getAuditorState()) == false)
        {
            message.setMessage("原料入库申请单审核状态必须是“通过”才能变更");
            return false;
        }
        
        // 验证
        RawMaterialInfo rawMaterialInfo = rawMaterialInfoDao.getRawMaterialInfoByCode(rawmaterialWarehouse.getRawmaterialCode());
        if (rawMaterialInfo == null)
        {
            message.setMessage("原料[" + rawmaterialWarehouse.getName() + "]不存在");
            return false;
        }
        
        Supplier supplier = rawmaterialWarehouseDao.getHibernateDao().getEntity(Supplier.class, rawmaterialWarehouse.getSupplierId());
        if (supplier == null)
        {
            message.setMessage("供应商不存在不存在");
            return false;
        }
        
        User user = rawmaterialWarehouseDao.getHibernateDao().getEntity(User.class, rawmaterialWarehouse.getAuditorId());
        if (user == null)
        {
            message.setMessage("流程审核人不存在");
            return false;
        }
        
        // 初始化审核时填写的数据
        rawmaterialWarehouse.setAuditorState(RawmaterialWarehouse.PENDING_AUDIT);
        rawmaterialWarehouse.setUnitPrice(new BigDecimal(0));
        rawmaterialWarehouse.setAggregateAmount(new BigDecimal(0));
        rawmaterialWarehouse.setIsInvoice(RawmaterialWarehouse.INVOICE_YES);
        rawmaterialWarehouse.setIsHistory(RawmaterialWarehouse.HISTORY_NO);
        // 设置已经变更
        rawmaterialWarehouse.setIsChange(RawmaterialWarehouse.CHANGE_YES);
        
        // 数据库保存变更的申请单
        rawmaterialWarehouseDao.getHibernateDao().getSession().evict(oldRawmaterialWarehouse);
        rawmaterialWarehouseDao.getHibernateDao().getSession().update(rawmaterialWarehouse);
        // 修改原料入库申请单原单的原料编号(增加历史信息)
        String warehouseNo = oldRawmaterialWarehouse.getWarehouseNo() + RawmaterialWarehouse.HISTORY_NO_SUFFIX;
        RawmaterialWarehouse historyRawmaterialWarehouse = rawmaterialWarehouseDao.getRawmaterialWarehouseByWarehouseNo(warehouseNo);
        if (historyRawmaterialWarehouse != null)
        {
            rawmaterialWarehouseDao.getHibernateDao().getSession().evict(historyRawmaterialWarehouse);
            oldRawmaterialWarehouse.setId(historyRawmaterialWarehouse.getId());
        }
        else
        {
            oldRawmaterialWarehouse.setId(null);
        }
        oldRawmaterialWarehouse.setIsHistory(RawmaterialWarehouse.HISTORY_YES);
        oldRawmaterialWarehouse.setWarehouseNo(warehouseNo);
        if (historyRawmaterialWarehouse == null)
        {
            rawmaterialWarehouseDao.getHibernateDao().getSession().save(oldRawmaterialWarehouse);
        }
        else
        {
            rawmaterialWarehouseDao.getHibernateDao().getSession().update(oldRawmaterialWarehouse);
        }
        return true;
    }
    
    /**
     * 查询用户需要审核的原料入库申请单数量
     * @param userId 查询参数：用户ID
     */
    public int getCountByAuditorId(Serializable userId)
    {
        return rawmaterialWarehouseDao.getCountByAuditorId(userId);
    }
    
    /**
     * 根据原料入库申请单编号查询申请单
     * @param warehouseNo 查询参数：原料入库申请单编号
     * @return 原料入库申请单以及关联信息
     */
    public Map<String, Object> getRawmaterialWarehouseByNo(String warehouseNo)
    {
        return rawmaterialWarehouseDao.getRawmaterialWarehouseByNo(warehouseNo);
    }
    
    /**
     * 获取原料入库审核人<br>
     * */
    public User getAuditorByRawmaterialWarehouse()
    {
        Dict dict = dictDao.getDictByTypeAndkey(AUDITOR_DICT_TYPE, AUDITOR_DICT_KEY);
        if (dict == null)
        {
            logger.error("获取原料入库审核人出错！请在配置字典[type=" + AUDITOR_DICT_TYPE + ",key=" + AUDITOR_DICT_KEY + "]");
            return null;
        }
        long userId = NumberUtils.toLong(dict.getDictValue(), -1L);
        if (userId == -1L)
        {
            logger.error("获取原料入库审核人出错！请在配置字典[type=" + AUDITOR_DICT_TYPE + ",key=" + AUDITOR_DICT_KEY + "]的值是可用的用户ID！");
            return null;
        }
        return rawmaterialWarehouseDao.getHibernateDao().getEntity(User.class, userId);
    }
}